#ifndef __SHARED__
#define __SHARED__

#include <windows.h>

#pragma pack(push, 1)
struct ImageHeader
{
  int updated;
  int width;
  int height;
  unsigned long offset;
};
struct FrameHeader : public ImageHeader
{
  int insetLeft;
  int insetTop;
  int insetRight;
  int insetBottom;
};
struct ScrollHeader : public ImageHeader
{
  int barTop;
  int barRight;
  int barBottom;
};
struct ReplyHeader : public ImageHeader
{
};
struct LineHeader : public ImageHeader
{
  int insetTop;
  int insetBottom;
};

#define WM_UPDATEREPLY    (WM_USER+700)
#define WM_POSTREPLY      (WM_USER+701)

struct SharedHeader
{
  unsigned long size;
  unsigned long end;
  unsigned long mutexid;
  union
  {
    HWND hWndLauncher;
    unsigned char force64_1[8];
  };

  int hidden;
  union
  {
    HWND hWnd;
    unsigned char force64_2[8];
  };
  int left;
  int top;
  int right;
  int bottom;

  int scrollPos;
  int maxScroll;

  wchar_t replyText[256];
  int replyPos[256];
  int replyCaret;
  int replySelStart;
  int replyScroll;
  int replyHotkey;

  int numLines;
  int maxLines;
  unsigned long offsFrame;
  unsigned long offsScroll;
  unsigned long offsReply;
  unsigned long offsLines;
};
#pragma pack(pop)

class SharedData
{
  HANDLE hFile;
  HANDLE hMutex;
  mutable HANDLE hMapFile;
  mutable unsigned char* pShared;
  mutable DWORD fileSize;
  SharedHeader* resize(int newSize);
  SharedHeader* growLines();
public:
  SharedData(bool master);
  ~SharedData();

  SharedHeader* lock(DWORD timeout = INFINITE) const;
  void unlock() const;

  SharedHeader* header() const
  {
    return (SharedHeader*) pShared;
  }
  unsigned long* bits(unsigned long offset)
  {
    return (unsigned long*) (pShared + offset);
  }
  unsigned long const* bits(unsigned long offset) const
  {
    return (unsigned long*) (pShared + offset);
  }
  FrameHeader* frame() const
  {
    return (FrameHeader*) (pShared + ((SharedHeader*) pShared)->offsFrame);
  }
  ScrollHeader* scroll() const
  {
    return (ScrollHeader*) (pShared + ((SharedHeader*) pShared)->offsScroll);
  }
  ReplyHeader* reply() const
  {
    return (ReplyHeader*) (pShared + ((SharedHeader*) pShared)->offsReply);
  }
  LineHeader* line(int i) const
  {
    return (LineHeader*) (pShared + ((SharedHeader*) pShared)->offsLines + sizeof(LineHeader) * i);
  }
  void popline(int i);

  SharedHeader* reset(int width, int height, int lines = 0);
  LineHeader* add(int width, int height);

  class Lock
  {
    SharedData const* m_data;
    bool m_locked;
  public:
    Lock(SharedData const* data, DWORD timeout = INFINITE)
      : m_data(data)
    {
      if (!data->lock(timeout))
        m_data = NULL;
    }
    ~Lock()
    {
      if (m_data)
        m_data->unlock();
    }
    bool locked() const
    {
      return (m_data != NULL);
    }
  };
};

#endif __SHARED__
